package com.cjq.core;

import com.cjq.config.GatewayConfig;
import com.cjq.core.filter.GatewayFilter;
import com.cjq.core.filter.GatewayFilterManger;
import com.cjq.core.loadblance.LoadBalancerManger;
import com.cjq.core.route.DynamicRouter;
import com.cjq.core.route.RouteDefinition;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import static io.netty.buffer.Unpooled.copiedBuffer;

@Slf4j
@Component
public class GatewayHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    private final DynamicRouter router;
    public final GatewayFilterManger filter;
    private final RestTemplate restTemplate;

    public GatewayHandler(GatewayConfig config) {
        this.router = new DynamicRouter(config);
        this.filter = new GatewayFilterManger(config);
        this.restTemplate = new RestTemplate();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        try {
            // 1. 执行前置过滤器链
            if (!applyPreFilters(ctx, request)) {
                exceptionCaught(ctx, new Throwable("执行前置过滤器失败"));
            }

            // 2. 路由匹配
            RouteDefinition route = router.match(request.uri());
            if (route == null) {
                exceptionCaught(ctx, new Throwable("路由为空"));
            }
            // 3. 负载均衡选择实例
            String targetUrl = LoadBalancerManger.select(route.getInstances());
            String endUrdl= request.getUri().replace(route.getPrefix(),"");
            String url = targetUrl+endUrdl;
            HttpHeaders headers = new HttpHeaders();
            ByteBuf bodyBuf = request.content();
            HttpEntity<String> entity = new HttpEntity<>(bodyBuf.toString(StandardCharsets.UTF_8), headers);
            ResponseEntity<String> res = restTemplate.postForEntity(url, entity, String.class);
            if (res != null) {
                FullHttpResponse responses = responseHandler(HttpResponseStatus.OK, res.getBody());
                applyPostFilters(ctx, null, responses);
                ctx.writeAndFlush(responses).addListener(ChannelFutureListener.CLOSE);
            } else {
                exceptionCaught(ctx, new Throwable("下游返回为空"));
            }
        } catch (Exception e) {
            exceptionCaught(ctx, new Throwable(e.getMessage()));
            ReferenceCountUtil.release(request);
        }
    }

    private boolean applyPreFilters(ChannelHandlerContext ctx, FullHttpRequest request) {
        for (GatewayFilter filter : filter.filters) {
            if (!filter.filter(request, ctx)) {
                return false;
            }
        }
        return true;
    }

    private void applyPostFilters(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
        filter.filters.forEach(filter -> filter.postFilter(req, res));
    }

    private FullHttpResponse responseHandler(HttpResponseStatus status, String responseContent) {
        ByteBuf content = copiedBuffer(responseContent, Charset.forName("utf-8"));
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content);
        return response;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        FullHttpResponse response = responseHandler(HttpResponseStatus.OK, cause.getMessage());
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}